package bt

import (
	common "app/util"
	"github.com/google/btree"
	"sync"
	"bytes"
)

type BtPeerSession struct{

	// ip to node
	pt			common.SMap
	//find index
	sbtree 		*btree.BTree
	//btree lock
	slock 		sync.RWMutex

}

func newBtPeerSession() *BtPeerSession {

	p := new(BtPeerSession)
	p.sbtree =  btree.New(1024* 1024)
	return p
}

func (p *BtPeerSession) NewPeer(res *Request) {

	pl := NewPeersList(res.IPKey)
	pl.SetNode(res.PeerId,res)

	p.pt.SetValue(res.IPKey,pl)

}
func (p *BtPeerSession) ReplacePeer(res *Request) {

	pl,err := p.pt.GetValue(res.IPKey)

	if err != nil {
		return
	}

	if plv,ok := pl.(*Peers); ok {
		plv.SetNode(res.PeerId,res)
	}
}
func (p *BtPeerSession) SetPeer(req *Request) {

	Item := p.sbtree.Get(btree.Int(req.IPKey))

	if _,ok := Item.(btree.Int); ok {
		p.ReplacePeer(req)
	} else {
		p.slock.Lock()
		p.sbtree.ReplaceOrInsert(btree.Int(req.IPKey))
		p.slock.Unlock()
		p.NewPeer(req)
	}
}

func (p *BtPeerSession) DelPeer(req *Request) {

	p.slock.Lock()
	//p.sbtree.Delete(btree.Int(req.IPKey))
	p.slock.Unlock()

	pl,err := p.pt.GetValue(req.IPKey)

	if err != nil {
		return
	}

	if plv,ok := pl.(*Peers); ok {
		plv.DelNode(req.PeerId)
	}

}

func (p *BtPeerSession) GetPeers(req *Request,size int) ([]byte) {

	buf := new(bytes.Buffer)

	prebuffer := p.GetNextPeers(req,size/2)
	buf.Write(prebuffer)

	nextbuffer := p.GetPreviousPeers(req,size/2)
	buf.Write(nextbuffer)

	return buf.Bytes()
}

func (p *BtPeerSession) GetPreviousPeers(req *Request,size int) ([]byte) {

	buf := new(bytes.Buffer)

	p.sbtree.AscendLessThan(btree.Int(req.IPKey),func(a btree.Item) bool {

		id := a.(btree.Int)

		v,err:= p.pt.GetValue(int(id))
		if err != nil{
			return true
		}

		///////////////////////////////////////////////////////////
		if value,ok := v.(*Peers); ok {

			f := func(k, v interface{}) bool {
				if vRes,ok := v.(*Request); ok {
					addr ,_ := common.AddrtoByte(vRes.IPAddress, vRes.Port)
					buf.Write(addr)
				}
				return true
			}
			value.RangNode(f)
		}
		///////////////////////////////////////////////////////////
		return true
	})

	return buf.Bytes()
}
func (p *BtPeerSession) GetNextPeers(req *Request,size int) ([]byte) {

	buf := new(bytes.Buffer)
	p.sbtree.AscendGreaterOrEqual(btree.Int(req.IPKey),func(a btree.Item) bool {

		id := a.(btree.Int)
		v,err:= p.pt.GetValue(int(id))
		if err != nil{
			return true
		}

		///////////////////////////////////////////////////////////
		if value,ok := v.(*Peers); ok {

			f := func(k, v interface{}) bool {
				if vRes,ok := v.(*Request); ok {
					addr ,_ := common.AddrtoByte(vRes.IPAddress, vRes.Port)
					buf.Write(addr)
				}
				return true
			}
			value.RangNode(f)
		}
		///////////////////////////////////////////////////////////

		return true
	})

	return buf.Bytes()
}

func (p *BtPeerSession)  GetPeerSize(typename string) int32 {


	index := new(int32)
	*index = 0


	//buf := new(bytes.Buffer)
	p.sbtree.Ascend(func(a btree.Item) bool {

		id := a.(btree.Int)
		v,err:= p.pt.GetValue(int(id))
		if err != nil{
			return true
		}

		///////////////////////////////////////////////////////////
		if value,ok := v.(*Peers); ok {

			f := func(k, v interface{}) bool {
				if vReq,ok := v.(*Request); ok {

					if typename == vReq.Event {
						*index += 1
					}
				}
				return true
			}
			value.RangNode(f)
		}
		return true
	})



	return *index;
}



